home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / editors / stevie.1 < prev    next >
Text File  |  1988-12-02  |  60KB  |  2,627 lines

  1. Path: xanth!mcnc!gatech!bloom-beacon!mit-eddie!ll-xn!adelie!infinet!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i081:  stevie - vi editor clone, Part01/04
  5. Message-ID: <10419@swan.ulowell.edu>
  6. Date: 2 Dec 88 01:42:33 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2616
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: grwalter@watcgl.waterloo.edu
  12. Posting-number: Volume 2, Issue 81
  13. Archive-name: editors/stevie.1
  14.  
  15. This is a source release of the STEVIE editor, a public domain clone
  16. of the UNIX editor 'vi'. The program was originally developed for the
  17. Atari ST, but has been ported to UNIX, OS/2, BSD 4.3 and the Amiga.
  18.  
  19. #    This is a shell archive.
  20. #    Remove everything above and including the cut line.
  21. #    Then run the rest of the file through sh.
  22. #----cut here-----cut here-----cut here-----cut here----#
  23. #!/bin/sh
  24. # shar:    Shell Archiver
  25. #    Run the following text with /bin/sh to create:
  26. #    Makefile
  27. #    README
  28. #    alloc.c
  29. #    amiga.c
  30. #    amiga.h
  31. #    ascii.h
  32. #    charset.c
  33. #    cmdline.c
  34. #    dec.c
  35. #    edit.c
  36. #    fileio.c
  37. #    help.c
  38. #    inc.c
  39. # This archive created: Thu Dec  1 20:37:03 1988
  40. cat << \SHAR_EOF > Makefile
  41. #
  42. # Makefile for Lattice C on Amiga
  43. #
  44.  
  45. .c.o:
  46.     lc $(CFLAGS) $<
  47.  
  48. LIBS = /regexp/regexp.lib
  49. LDFLAGS=
  50.  
  51. CFLAGS = -cu -dAUTO_INDENT
  52. LINKFLAGS = NODEBUG
  53.  
  54. MACH=    amiga.o raw.o sendpacket.o
  55.  
  56. OBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  57.     updateRealscreen.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  58.     updateNextscreen.o mark.o screen.o fileio.o param.o $(MACH)
  59.  
  60. all : stevie
  61.  
  62. stevie : $(OBJ)
  63.     BLINK TO stevie FROM lib:c.o $(OBJ) \
  64.         LIBRARY $(LIBS) lib:lc.lib lib:amiga.lib \
  65.         $(LINKFLAGS)
  66.  
  67. clean :
  68.     delete $(OBJ)
  69. SHAR_EOF
  70. cat << \SHAR_EOF > README
  71. STEVIE Source Release
  72.  
  73. This is a source release of the STEVIE editor, a public domain clone
  74. of the UNIX editor 'vi'. The program was originally developed for the
  75. Atari ST, but has been ported to UNIX, OS/2, BSD 4.3 and the Amiga as well.
  76.  
  77. To compile STEVIE, you'll also need Henry Spencer's regular expression
  78. library.
  79.  
  80. The files included in this release are:
  81.  
  82. README
  83.     This file.
  84.  
  85. stevie.doc
  86.     Reference manual for STEVIE. Assumes familiarity with vi.
  87.  
  88. source.doc
  89.     Quick overview of the major data structures used.
  90.  
  91. porting.doc
  92.     Tips for porting STEVIE to other systems.
  93.  
  94. makefile.os2
  95. makefile.usg
  96. makefile.tos
  97. makefile.bsd
  98. makefile.amiga.lattice
  99.     Makefiles for OS/2, UNIX System V, Atari ST, BSD 4.3 UNIX and the
  100. Amiga respectively.
  101.  
  102. amiga.c
  103. amiga.h
  104. bsd.c
  105. bsd.h
  106. os2.c
  107. os2.h
  108. unix.c
  109. unix.h
  110. tos.c
  111. tos.h
  112.     System-dependent routines for the same.
  113.  
  114. alloc.c ascii.h cmdline.c edit.c fileio.c help.c charset.c
  115. keymap.h linefunc.c main.c mark.c misccmds.c normal.c param.c
  116. param.h ptrfunc.c screen.c search.c stevie.h term.h macros.h
  117.  
  118.     C source and header files for STEVIE.
  119.  
  120. To compile STEVIE for one of the provided systems:
  121.  
  122.     1. Compile the regular expression library and install as
  123.        appropriate for your system.
  124.  
  125.     2. Edit the file 'stevie.h' to set the system defines as needed.
  126.  
  127.     3. Check the makefile for your system, and modify as needed.
  128.  
  129.     4. Compile.
  130.  
  131. Good Luck...
  132.  
  133. Tony Andrews            March  12, 1988
  134. G. R. (Fred) Walter     August 14, 1988
  135. SHAR_EOF
  136. cat << \SHAR_EOF > alloc.c
  137. /*
  138.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  139.  *
  140.  * Code Contributions By : Tim Thompson           twitch!tjt
  141.  *                         Tony Andrews           onecom!wldrdg!tony 
  142.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  143.  */
  144.  
  145. #include "stevie.h"
  146.  
  147. /*
  148.  * This file contains various routines dealing with allocation and
  149.  * deallocation of data structures. 
  150.  */
  151.  
  152. char           *
  153. alloc(size)
  154.     unsigned        size;
  155. {
  156.     char           *p;        /* pointer to new storage space */
  157.  
  158.     p = malloc(size);
  159.     if (p == (char *) NULL) {    /* if there is no more room... */
  160.     emsg("alloc() is unable to find memory!");
  161.     }
  162.     return (p);
  163. }
  164.  
  165. char           *
  166. strsave(string)
  167.     char           *string;
  168. {
  169.     return (strcpy(alloc((unsigned) (strlen(string) + 1)), string));
  170. }
  171.  
  172. void
  173. screenalloc()
  174. {
  175.     /*
  176.      * If we're changing the size of the screen, free the old arrays 
  177.      */
  178.     if (Realscreen != NULL)
  179.     free(Realscreen);
  180.     if (Nextscreen != NULL)
  181.     free(Nextscreen);
  182.  
  183.     Realscreen = malloc((unsigned) (Rows * Columns));
  184.     Nextscreen = malloc((unsigned) (Rows * Columns));
  185. }
  186.  
  187. /*
  188.  * Allocate and initialize a new line structure with room for 'nchars'
  189.  * characters. 
  190.  */
  191. LINE           *
  192. newline(nchars)
  193.     int             nchars;
  194. {
  195.     LINE           *l;
  196.  
  197.     l = (LINE *) alloc((unsigned) sizeof(LINE));
  198.     if (l == NULL)
  199.     return (LINE *) NULL;
  200.  
  201.     l->s = alloc((unsigned) nchars);    /* the line is empty */
  202.     l->s[0] = NUL;
  203.     l->size = nchars;
  204.  
  205.     l->prev = (LINE *) NULL;    /* should be initialized by caller */
  206.     l->next = (LINE *) NULL;
  207.  
  208.     return l;
  209. }
  210.  
  211. /*
  212.  * filealloc() - construct an initial empty file buffer 
  213.  */
  214. void
  215. filealloc()
  216. {
  217.     if ((Filemem->linep = newline(1)) == NULL) {
  218.     fprintf(stderr, "Unable to allocate file memory!\n");
  219.     getout(1);
  220.     }
  221.     if ((Fileend->linep = newline(1)) == NULL) {
  222.     fprintf(stderr, "Unable to allocate file memory!\n");
  223.     getout(1);
  224.     }
  225.     Filemem->index = 0;
  226.     Fileend->index = 0;
  227.  
  228.     Filemem->linep->next = Fileend->linep;
  229.     Fileend->linep->prev = Filemem->linep;
  230.  
  231.     *Curschar = *Filemem;
  232.     *Topchar = *Filemem;
  233.  
  234.     Filemem->linep->num = 0;
  235.     Fileend->linep->num = 0xffff;
  236.  
  237.     clrall();            /* clear all marks */
  238. }
  239.  
  240. /*
  241.  * freeall() - free the current buffer 
  242.  *
  243.  * Free all lines in the current buffer. 
  244.  */
  245. void
  246. freeall()
  247. {
  248.     LINE           *lp, *xlp;
  249.  
  250.     for (lp = Filemem->linep; lp != NULL; lp = xlp) {
  251.     if (lp->s != NULL)
  252.         free(lp->s);
  253.     xlp = lp->next;
  254.     free((char *) lp);
  255.     }
  256.  
  257.     Curschar->linep = NULL;    /* clear pointers */
  258.     Filemem->linep = NULL;
  259.     Fileend->linep = NULL;
  260. }
  261.  
  262. /*
  263.  * canincrease(n) - returns TRUE if the current line can be increased 'n'
  264.  * bytes 
  265.  *
  266.  * This routine returns immediately if the requested space is available. If not,
  267.  * it attempts to allocate the space and adjust the data structures
  268.  * accordingly. If everything fails it returns FALSE. 
  269.  */
  270. bool_t
  271. canincrease(n)
  272.     int             n;
  273. {
  274.     int             nsize;
  275.     char           *s;        /* pointer to new space */
  276.  
  277.     nsize = strlen(Curschar->linep->s) + 1 + n;    /* size required */
  278.  
  279.     if (nsize <= Curschar->linep->size)
  280.     return TRUE;
  281.  
  282.     /*
  283.      * Need to allocate more space for the string. Allow some extra space on
  284.      * the assumption that we may need it soon. This avoids excessive numbers
  285.      * of calls to malloc while entering new text. 
  286.      */
  287.     s = alloc((unsigned) (nsize + SLOP));
  288.     if (s == NULL) {
  289.     emsg("Can't add anything, file is too big!");
  290.     State = NORMAL;
  291.     return FALSE;
  292.     }
  293.     Curschar->linep->size = nsize + SLOP;
  294.     strcpy(s, Curschar->linep->s);
  295.     free(Curschar->linep->s);
  296.     Curschar->linep->s = s;
  297.  
  298.     return TRUE;
  299. }
  300. SHAR_EOF
  301. cat << \SHAR_EOF > amiga.c
  302. /*
  303.  * Amiga system-dependent routines. 
  304.  */
  305.  
  306. #include "stevie.h"
  307.  
  308. long            stdin_file_handle = 0;
  309.  
  310. int
  311. GetCharacter()
  312. {
  313.     char            c;
  314.  
  315.     Read(stdin_file_handle, &c, sizeof(c));
  316.     return ((int) c);
  317. }
  318.  
  319. /*
  320.  * getCSIsequence - get a CSI sequence
  321.  *                - either cursor keys, help, functionkeys, or some
  322.  *                  other sequence (if other, check window size)
  323.  */
  324. int
  325. getCSIsequence()
  326. {
  327.     int             c;
  328.     int             param1;
  329.     int             param2;
  330.  
  331.     c = GetCharacter();
  332.     if (isdigit(c)) {
  333.     param1 = 0;
  334.     while (isdigit(c)) {
  335.         param1 = param1 * 10 + c - '0';
  336.         c = GetCharacter();
  337.     }
  338.     if (c == '~')        /* function key */
  339.         return ((char) (K_F1 + param1));
  340.  
  341.     /* must be an event of some sort or a window bound report */
  342.     if (c == ';') {
  343.         param2 = 0;
  344.         c = GetCharacter();
  345.         while (isdigit(c)) {
  346.         param2 = param2 * 10 + c - '0';
  347.         c = GetCharacter();
  348.         }
  349.         if (c == ';') {
  350.         param1 = 0;
  351.         c = GetCharacter();
  352.         while (isdigit(c)) {
  353.             param1 = param1 * 10 + c - '0';
  354.             c = GetCharacter();
  355.         }
  356.         if (c == ';') {
  357.             param2 = 0;
  358.             c = GetCharacter();
  359.             while (isdigit(c)) {
  360.             param2 = param2 * 10 + c - '0';
  361.             c = GetCharacter();
  362.             }
  363.             if (c == ' ') {
  364.             c = GetCharacter();
  365.             if (c == 'r') {
  366.                 if (param1 < 2)
  367.                 param1 = 2;
  368.                 if (param2 < 5)
  369.                 param2 = 5;
  370.                 if (Columns != param2 || Rows != param1) {
  371.                 Columns = param2;
  372.                 Rows = param1;
  373.                 P(P_LI) = Rows;
  374.                 return (-1);
  375.                 } else
  376.                 return 0;
  377.             }
  378.             }
  379.         }
  380.         }
  381.     }
  382.     while ((c != '|') && (c != '~'))
  383.         c = GetCharacter();
  384.  
  385.     outstr("\033[0 q");
  386.     fflush(stdout); /* flush out the window size request */
  387.     return 0;
  388.     }
  389.     switch (c) {
  390.       case 'A':        /* cursor up */
  391.     return K_UARROW;
  392.       case 'B':        /* cursor down */
  393.     return K_DARROW;
  394.       case 'C':        /* cursor right */
  395.     return K_RARROW;
  396.       case 'D':        /* cursor left */
  397.     return K_LARROW;
  398.       case 'T':        /* shift cursor up */
  399.     return K_SUARROW;
  400.       case 'S':        /* shift cursor down */
  401.     return K_SDARROW;
  402.       case ' ':        /* shift cursor left or right */
  403.     c = GetCharacter();
  404.     if (c == 'A')        /* shift cursor left */
  405.         return K_SLARROW;
  406.     if (c == '@')        /* shift cursor right */
  407.         return K_SRARROW;
  408.     break;
  409.       case '?':        /* help */
  410.     c = GetCharacter();
  411.     if (c == '~')
  412.         return K_HELP;
  413.     break;
  414.     }
  415.     return 0;            /* some other control code */
  416. }
  417.  
  418. /*
  419.  * inchar() - get a character from the keyboard 
  420.  */
  421. char
  422. inchar()
  423. {
  424.     int             c;
  425.  
  426.     fflush(stdout); /* flush any pending output */
  427.  
  428.     for (;;) {
  429.     c = GetCharacter();
  430.     if (c != 0x9b)
  431.         break;
  432.     c = getCSIsequence();
  433.     if (c > 0)
  434.         break;
  435.     if (c == -1) {
  436.         screenalloc();
  437.         screenclear();
  438.         updateNextscreen();
  439.         updateRealscreen();
  440.         msg("");
  441.         cursupdate();
  442.         windgoto(Cursrow, Curscol);
  443.         fflush(stdout);
  444.     }
  445.     }
  446.     return (char) c;
  447. }
  448.  
  449. void
  450. outstr(s)
  451.     char           *s;
  452. {
  453.     while (*s)
  454.     outchar(*s++);
  455. }
  456.  
  457. void
  458. beep()
  459. {
  460.     if (RedrawingDisabled)
  461.     return;
  462.  
  463.     outchar('\007');
  464. }
  465.  
  466. void
  467. sleep(n)
  468.     int             n;
  469. {
  470.     void            Delay();
  471.  
  472.     if (n > 0)
  473.     Delay(50L * n);
  474. }
  475.  
  476. void
  477. delay()
  478. {
  479.     void            Delay();
  480.  
  481.     Delay(25L);
  482. }
  483.  
  484. void
  485. windinit()
  486. {
  487.     stdin_file_handle = Input();
  488.     if (!IsInteractive(stdin_file_handle)) {
  489.     fprintf(stderr, "stdin is not interactive ?!?!?!?");
  490.     exit(2);
  491.     }
  492.  
  493.     Columns = 80;
  494.     P(P_LI) = Rows = 24;
  495.     if (raw(stdin) != 0)
  496.     perror("raw");
  497.  
  498.     outstr("\033[12{");        /* window resize events activated */
  499.     outstr("\033[0 q");        /* get window size */
  500.     fflush(stdout);
  501.  
  502.     for (;;) {
  503.     if (GetCharacter() == 0x9b)
  504.         if (getCSIsequence() == -1)
  505.         break;
  506.     }
  507. }
  508.  
  509. void
  510. windexit(r)
  511.     int             r;
  512. {
  513.     outstr("\033[12}");        /* window resize events de-activated */
  514.     fflush(stdout);         /* flush any pending output */
  515.  
  516.  
  517.     if (cooked(stdin) != 0)
  518.     perror("cooked");
  519.     exit(r);
  520. }
  521.  
  522. void
  523. windgoto(r, c)
  524.     int             c;
  525.     int             r;
  526. {
  527.     r++;
  528.     c++;
  529.  
  530.     outstr("\033[");
  531.     if (r >= 10)
  532.     outchar((char) (r / 10 + '0'));
  533.     outchar((char) (r % 10 + '0'));
  534.     outchar(';');
  535.     if (c >= 10)
  536.     outchar((char) (c / 10 + '0'));
  537.     outchar((char) (c % 10 + '0'));
  538.     outchar('H');
  539. }
  540.  
  541. FILE           *
  542. fopenb(fname, mode)
  543.     char           *fname;
  544.     char           *mode;
  545. {
  546.     FILE           *fopen();
  547.     char            modestr[16];
  548.  
  549.     sprintf(modestr, "%sb", mode);
  550.     return fopen(fname, modestr);
  551. }
  552. SHAR_EOF
  553. cat << \SHAR_EOF > amiga.h
  554. /*
  555.  * Amiga Machine-dependent routines. 
  556.  */
  557. char inchar();
  558. #define outchar(c) putchar(c)
  559. void outstr();
  560. void beep();
  561. void windinit(), windexit(), windgoto();
  562. void delay();
  563. void sleep();
  564. SHAR_EOF
  565. cat << \SHAR_EOF > ascii.h
  566. /*
  567.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  568.  *
  569.  * Code Contributions By : Tim Thompson           twitch!tjt
  570.  *                         Tony Andrews           onecom!wldrdg!tony 
  571.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  572.  */
  573.  
  574. /*
  575.  * Definitions of various common control characters 
  576.  */
  577.  
  578. #define    NUL        '\000'
  579. #define    BS        '\010'
  580. #define    TAB        '\011'
  581. #define    NL        '\012'
  582. #define    NL_STR        "\012"
  583. #define    CR        '\015'
  584. #define    ESC        '\033'
  585. #define    ESC_STR        "\033"
  586.  
  587. #define    UNDO_SHIFTJ    '\333'
  588. #define    UNDO_SHIFTJ_STR    "\333"
  589.  
  590. #define    CTRL(x)    ((x) & 0x1f)
  591. SHAR_EOF
  592. cat << \SHAR_EOF > charset.c
  593. /*
  594.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  595.  *
  596.  * Code Contributions By : Tim Thompson           twitch!tjt
  597.  *                         Tony Andrews           onecom!wldrdg!tony 
  598.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  599.  */
  600.  
  601. #include "stevie.h"
  602.  
  603. /*
  604.  * This file shows how to display characters on the screen. This is approach
  605.  * is something of an overkill. It's a remnant from the original code that
  606.  * isn't worth messing with for now. TABS are special-cased depending on the
  607.  * value of the "list" parameter. 
  608.  */
  609.  
  610. struct charinfo chars[] = {
  611.                 /* 0 */ 1, NUL,
  612.                 /* 1 */ 2, "^A",
  613.                 /* 2 */ 2, "^B",
  614.                 /* 3 */ 2, "^C",
  615.                 /* 4 */ 2, "^D",
  616.                 /* 5 */ 2, "^E",
  617.                 /* 6 */ 2, "^F",
  618.                 /* 7 */ 2, "^G",
  619.                 /* 8 */ 2, "^H",
  620.                 /* 9 */ 2, "^I",
  621.                 /* 10 */ 7, "[ERROR]",    /* shouldn't happen */
  622.                 /* 11 */ 2, "^K",
  623.                 /* 12 */ 2, "^L",
  624.                 /* 13 */ 2, "^M",
  625.                 /* 14 */ 2, "^N",
  626.                 /* 15 */ 2, "^O",
  627.                 /* 16 */ 2, "^P",
  628.                 /* 17 */ 2, "^Q",
  629.                 /* 18 */ 2, "^R",
  630.                 /* 19 */ 2, "^S",
  631.                 /* 20 */ 2, "^T",
  632.                 /* 21 */ 2, "^U",
  633.                 /* 22 */ 2, "^V",
  634.                 /* 23 */ 2, "^W",
  635.                 /* 24 */ 2, "^X",
  636.                 /* 25 */ 2, "^Y",
  637.                 /* 26 */ 2, "^Z",
  638.                 /* 27 */ 2, "^[",
  639.                 /* 28 */ 2, "^\\",
  640.                 /* 29 */ 2, "^]",
  641.                 /* 30 */ 2, "^^",
  642.                 /* 31 */ 2, "^_",
  643.                 /* 32 */ 1, " ",
  644.                 /* 33 */ 1, "!",
  645.                 /* 34 */ 1, "\"",
  646.                 /* 35 */ 1, "#",
  647.                 /* 36 */ 1, "$",
  648.                 /* 37 */ 1, "%",
  649.                 /* 38 */ 1, "&",
  650.                 /* 39 */ 1, "'",
  651.                 /* 40 */ 1, "(",
  652.                 /* 41 */ 1, ")",
  653.                 /* 42 */ 1, "*",
  654.                 /* 43 */ 1, "+",
  655.                 /* 44 */ 1, ",",
  656.                 /* 45 */ 1, "-",
  657.                 /* 46 */ 1, ".",
  658.                 /* 47 */ 1, "/",
  659.                 /* 48 */ 1, "0",
  660.                 /* 49 */ 1, "1",
  661.                 /* 50 */ 1, "2",
  662.                 /* 51 */ 1, "3",
  663.                 /* 52 */ 1, "4",
  664.                 /* 53 */ 1, "5",
  665.                 /* 54 */ 1, "6",
  666.                 /* 55 */ 1, "7",
  667.                 /* 56 */ 1, "8",
  668.                 /* 57 */ 1, "9",
  669.                 /* 58 */ 1, ":",
  670.                 /* 59 */ 1, ";",
  671.                 /* 60 */ 1, "<",
  672.                 /* 61 */ 1, "=",
  673.                 /* 62 */ 1, ">",
  674.                 /* 63 */ 1, "?",
  675.                 /* 64 */ 1, "@",
  676.                 /* 65 */ 1, "A",
  677.                 /* 66 */ 1, "B",
  678.                 /* 67 */ 1, "C",
  679.                 /* 68 */ 1, "D",
  680.                 /* 69 */ 1, "E",
  681.                 /* 70 */ 1, "F",
  682.                 /* 71 */ 1, "G",
  683.                 /* 72 */ 1, "H",
  684.                 /* 73 */ 1, "I",
  685.                 /* 74 */ 1, "J",
  686.                 /* 75 */ 1, "K",
  687.                 /* 76 */ 1, "L",
  688.                 /* 77 */ 1, "M",
  689.                 /* 78 */ 1, "N",
  690.                 /* 79 */ 1, "O",
  691.                 /* 80 */ 1, "P",
  692.                 /* 81 */ 1, "Q",
  693.                 /* 82 */ 1, "R",
  694.                 /* 83 */ 1, "S",
  695.                 /* 84 */ 1, "T",
  696.                 /* 85 */ 1, "U",
  697.                 /* 86 */ 1, "V",
  698.                 /* 87 */ 1, "W",
  699.                 /* 88 */ 1, "X",
  700.                 /* 89 */ 1, "Y",
  701.                 /* 90 */ 1, "Z",
  702.                 /* 91 */ 1, "[",
  703.                 /* 92 */ 1, "\\",
  704.                 /* 93 */ 1, "]",
  705.                 /* 94 */ 1, "^",
  706.                 /* 95 */ 1, "_",
  707.                 /* 96 */ 1, "`",
  708.                 /* 97 */ 1, "a",
  709.                 /* 98 */ 1, "b",
  710.                 /* 99 */ 1, "c",
  711.                 /* 100 */ 1, "d",
  712.                 /* 101 */ 1, "e",
  713.                 /* 102 */ 1, "f",
  714.                 /* 103 */ 1, "g",
  715.                 /* 104 */ 1, "h",
  716.                 /* 105 */ 1, "i",
  717.                 /* 106 */ 1, "j",
  718.                 /* 107 */ 1, "k",
  719.                 /* 108 */ 1, "l",
  720.                 /* 109 */ 1, "m",
  721.                 /* 110 */ 1, "n",
  722.                 /* 111 */ 1, "o",
  723.                 /* 112 */ 1, "p",
  724.                 /* 113 */ 1, "q",
  725.                 /* 114 */ 1, "r",
  726.                 /* 115 */ 1, "s",
  727.                 /* 116 */ 1, "t",
  728.                 /* 117 */ 1, "u",
  729.                 /* 118 */ 1, "v",
  730.                 /* 119 */ 1, "w",
  731.                 /* 120 */ 1, "x",
  732.                 /* 121 */ 1, "y",
  733.                 /* 122 */ 1, "z",
  734.                 /* 123 */ 1, "{",
  735.                 /* 124 */ 1, "|",
  736.                 /* 125 */ 1, "}",
  737.                 /* 126 */ 1, "~",
  738.                 /* 127 */ 2, "^?",
  739.                 /* 128 */ 5, "[128]",
  740.                 /* 129 */ 5, "[129]",
  741.                 /* 130 */ 5, "[130]",
  742.                 /* 131 */ 5, "[131]",
  743.                 /* 132 */ 5, "[132]",
  744.                 /* 133 */ 5, "[133]",
  745.                 /* 134 */ 5, "[134]",
  746.                 /* 135 */ 5, "[135]",
  747.                 /* 136 */ 5, "[136]",
  748.                 /* 137 */ 5, "[137]",
  749.                 /* 138 */ 5, "[138]",
  750.                 /* 139 */ 5, "[139]",
  751.                 /* 140 */ 5, "[140]",
  752.                 /* 141 */ 5, "[141]",
  753.                 /* 142 */ 5, "[142]",
  754.                 /* 143 */ 5, "[143]",
  755.                 /* 144 */ 5, "[144]",
  756.                 /* 145 */ 5, "[145]",
  757.                 /* 146 */ 5, "[146]",
  758.                 /* 147 */ 5, "[147]",
  759.                 /* 148 */ 5, "[148]",
  760.                 /* 149 */ 5, "[149]",
  761.                 /* 150 */ 5, "[150]",
  762.                 /* 151 */ 5, "[151]",
  763.                 /* 152 */ 5, "[152]",
  764.                 /* 153 */ 5, "[153]",
  765.                 /* 154 */ 5, "[154]",
  766.                 /* 155 */ 5, "[155]",
  767.                 /* 156 */ 5, "[156]",
  768.                 /* 157 */ 5, "[157]",
  769.                 /* 158 */ 5, "[158]",
  770.                 /* 159 */ 5, "[159]",
  771. #ifdef AMIGA
  772.                 /* 160 */ 1, "\240",
  773.                 /* 161 */ 1, "\241",
  774.                 /* 162 */ 1, "\242",
  775.                 /* 163 */ 1, "\243",
  776.                 /* 164 */ 1, "\244",
  777.                 /* 165 */ 1, "\245",
  778.                 /* 166 */ 1, "\246",
  779.                 /* 167 */ 1, "\247",
  780.                 /* 168 */ 1, "\250",
  781.                 /* 169 */ 1, "\251",
  782.                 /* 170 */ 1, "\252",
  783.                 /* 171 */ 1, "\253",
  784.                 /* 172 */ 1, "\254",
  785.                 /* 173 */ 1, "\255",
  786.                 /* 174 */ 1, "\256",
  787.                 /* 175 */ 1, "\257",
  788.                 /* 176 */ 1, "\260",
  789.                 /* 177 */ 1, "\261",
  790.                 /* 178 */ 1, "\262",
  791.                 /* 179 */ 1, "\263",
  792.                 /* 180 */ 1, "\264",
  793.                 /* 181 */ 1, "\265",
  794.                 /* 182 */ 1, "\266",
  795.                 /* 183 */ 1, "\267",
  796.                 /* 184 */ 1, "\270",
  797.                 /* 185 */ 1, "\271",
  798.                 /* 186 */ 1, "\272",
  799.                 /* 187 */ 1, "\273",
  800.                 /* 188 */ 1, "\274",
  801.                 /* 189 */ 1, "\275",
  802.                 /* 190 */ 1, "\276",
  803.                 /* 191 */ 1, "\277",
  804.                 /* 192 */ 1, "\300",
  805.                 /* 193 */ 1, "\301",
  806.                 /* 194 */ 1, "\302",
  807.                 /* 195 */ 1, "\303",
  808.                 /* 196 */ 1, "\304",
  809.                 /* 197 */ 1, "\305",
  810.                 /* 198 */ 1, "\306",
  811.                 /* 199 */ 1, "\307",
  812.                 /* 200 */ 1, "\310",
  813.                 /* 201 */ 1, "\311",
  814.                 /* 202 */ 1, "\312",
  815.                 /* 203 */ 1, "\313",
  816.                 /* 204 */ 1, "\314",
  817.                 /* 205 */ 1, "\315",
  818.                 /* 206 */ 1, "\316",
  819.                 /* 207 */ 1, "\317",
  820.                 /* 208 */ 1, "\320",
  821.                 /* 209 */ 1, "\321",
  822.                 /* 210 */ 1, "\322",
  823.                 /* 211 */ 1, "\323",
  824.                 /* 212 */ 1, "\324",
  825.                 /* 213 */ 1, "\325",
  826.                 /* 214 */ 1, "\326",
  827.                 /* 215 */ 1, "\327",
  828.                 /* 216 */ 1, "\330",
  829.                 /* 217 */ 1, "\331",
  830.                 /* 218 */ 1, "\332",
  831.                 /* 219 */ 1, "\333",
  832.                 /* 220 */ 1, "\334",
  833.                 /* 221 */ 1, "\335",
  834.                 /* 222 */ 1, "\336",
  835.                 /* 223 */ 1, "\337",
  836.                 /* 224 */ 1, "\340",
  837.                 /* 225 */ 1, "\341",
  838.                 /* 226 */ 1, "\342",
  839.                 /* 227 */ 1, "\343",
  840.                 /* 228 */ 1, "\344",
  841.                 /* 229 */ 1, "\345",
  842.                 /* 230 */ 1, "\346",
  843.                 /* 231 */ 1, "\347",
  844.                 /* 232 */ 1, "\350",
  845.                 /* 233 */ 1, "\351",
  846.                 /* 234 */ 1, "\352",
  847.                 /* 235 */ 1, "\353",
  848.                 /* 236 */ 1, "\354",
  849.                 /* 237 */ 1, "\355",
  850.                 /* 238 */ 1, "\356",
  851.                 /* 239 */ 1, "\357",
  852.                 /* 240 */ 1, "\360",
  853.                 /* 241 */ 1, "\361",
  854.                 /* 242 */ 1, "\362",
  855.                 /* 243 */ 1, "\363",
  856.                 /* 244 */ 1, "\364",
  857.                 /* 245 */ 1, "\365",
  858.                 /* 246 */ 1, "\366",
  859.                 /* 247 */ 1, "\367",
  860.                 /* 248 */ 1, "\370",
  861.                 /* 249 */ 1, "\371",
  862.                 /* 250 */ 1, "\372",
  863.                 /* 251 */ 1, "\373",
  864.                 /* 252 */ 1, "\374",
  865.                 /* 253 */ 1, "\375",
  866.                 /* 254 */ 1, "\376",
  867.                 /* 255 */ 1, "\377"
  868. #else
  869.                 /* 160 */ 5, "[160]",
  870.                 /* 161 */ 5, "[161]",
  871.                 /* 162 */ 5, "[162]",
  872.                 /* 163 */ 5, "[163]",
  873.                 /* 164 */ 5, "[164]",
  874.                 /* 165 */ 5, "[165]",
  875.                 /* 166 */ 5, "[166]",
  876.                 /* 167 */ 5, "[167]",
  877.                 /* 168 */ 5, "[168]",
  878.                 /* 169 */ 5, "[169]",
  879.                 /* 170 */ 5, "[170]",
  880.                 /* 171 */ 5, "[171]",
  881.                 /* 172 */ 5, "[172]",
  882.                 /* 173 */ 5, "[173]",
  883.                 /* 174 */ 5, "[174]",
  884.                 /* 175 */ 5, "[175]",
  885.                 /* 176 */ 5, "[176]",
  886.                 /* 177 */ 5, "[177]",
  887.                 /* 178 */ 5, "[178]",
  888.                 /* 179 */ 5, "[179]",
  889.                 /* 180 */ 5, "[180]",
  890.                 /* 181 */ 5, "[181]",
  891.                 /* 182 */ 5, "[182]",
  892.                 /* 183 */ 5, "[183]",
  893.                 /* 184 */ 5, "[184]",
  894.                 /* 185 */ 5, "[185]",
  895.                 /* 186 */ 5, "[186]",
  896.                 /* 187 */ 5, "[187]",
  897.                 /* 188 */ 5, "[188]",
  898.                 /* 189 */ 5, "[189]",
  899.                 /* 190 */ 5, "[190]",
  900.                 /* 191 */ 5, "[191]",
  901.                 /* 192 */ 5, "[192]",
  902.                 /* 193 */ 5, "[193]",
  903.                 /* 194 */ 5, "[194]",
  904.                 /* 195 */ 5, "[195]",
  905.                 /* 196 */ 5, "[196]",
  906.                 /* 197 */ 5, "[197]",
  907.                 /* 198 */ 5, "[198]",
  908.                 /* 199 */ 5, "[199]",
  909.                 /* 200 */ 5, "[200]",
  910.                 /* 201 */ 5, "[201]",
  911.                 /* 202 */ 5, "[202]",
  912.                 /* 203 */ 5, "[203]",
  913.                 /* 204 */ 5, "[204]",
  914.                 /* 205 */ 5, "[205]",
  915.                 /* 206 */ 5, "[206]",
  916.                 /* 207 */ 5, "[207]",
  917.                 /* 208 */ 5, "[208]",
  918.                 /* 209 */ 5, "[209]",
  919.                 /* 210 */ 5, "[210]",
  920.                 /* 211 */ 5, "[211]",
  921.                 /* 212 */ 5, "[212]",
  922.                 /* 213 */ 5, "[213]",
  923.                 /* 214 */ 5, "[214]",
  924.                 /* 215 */ 5, "[215]",
  925.                 /* 216 */ 5, "[216]",
  926.                 /* 217 */ 5, "[217]",
  927.                 /* 218 */ 5, "[218]",
  928.                 /* 219 */ 5, "[219]",
  929.                 /* 220 */ 5, "[220]",
  930.                 /* 221 */ 5, "[221]",
  931.                 /* 222 */ 5, "[222]",
  932.                 /* 223 */ 5, "[223]",
  933.                 /* 224 */ 5, "[224]",
  934.                 /* 225 */ 5, "[225]",
  935.                 /* 226 */ 5, "[226]",
  936.                 /* 227 */ 5, "[227]",
  937.                 /* 228 */ 5, "[228]",
  938.                 /* 229 */ 5, "[229]",
  939.                 /* 230 */ 5, "[230]",
  940.                 /* 231 */ 5, "[231]",
  941.                 /* 232 */ 5, "[232]",
  942.                 /* 233 */ 5, "[233]",
  943.                 /* 234 */ 5, "[234]",
  944.                 /* 235 */ 5, "[235]",
  945.                 /* 236 */ 5, "[236]",
  946.                 /* 237 */ 5, "[237]",
  947.                 /* 238 */ 5, "[238]",
  948.                 /* 239 */ 5, "[239]",
  949.                 /* 240 */ 5, "[240]",
  950.                 /* 241 */ 5, "[241]",
  951.                 /* 242 */ 5, "[242]",
  952.                 /* 243 */ 5, "[243]",
  953.                 /* 244 */ 5, "[244]",
  954.                 /* 245 */ 5, "[245]",
  955.                 /* 246 */ 5, "[246]",
  956.                 /* 247 */ 5, "[247]",
  957.                 /* 248 */ 5, "[248]",
  958.                 /* 249 */ 5, "[249]",
  959.                 /* 250 */ 5, "[250]",
  960.                 /* 251 */ 5, "[251]",
  961.                 /* 252 */ 5, "[252]",
  962.                 /* 253 */ 5, "[253]",
  963.                 /* 254 */ 5, "[254]",
  964.                 /* 255 */ 5, "[255]"
  965. #endif
  966. };
  967. SHAR_EOF
  968. cat << \SHAR_EOF > cmdline.c
  969. /*
  970.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  971.  *
  972.  * Code Contributions By : Tim Thompson           twitch!tjt
  973.  *                         Tony Andrews           onecom!wldrdg!tony 
  974.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  975.  */
  976.  
  977. #include "stevie.h"
  978.  
  979. static char    *altfile = NULL;    /* alternate file */
  980. static int      altline;    /* line # in alternate file */
  981.  
  982. static char    *nowrtmsg = "No write since last change (use ! to override)";
  983.  
  984. extern char   **files;        /* used for "n" and "rew" */
  985. extern int      curfile;
  986. extern int      numfiles;
  987.  
  988. /*
  989.  * The next two variables contain the bounds of any range given in a command.
  990.  * If no range was given, both contain null line pointers. If only a single
  991.  * line was given, u_pos will contain a null line pointer. 
  992.  */
  993. static LPTR     l_pos, u_pos;
  994.  
  995. static bool_t   interactive;    /* TRUE if we're reading a real command line */
  996.  
  997. static bool_t   doecmd();
  998. static void
  999. badcmd(), doshell(), get_range();
  1000. static LPTR    *get_line();
  1001.  
  1002. #ifdef    MEGAMAX
  1003. overlay "cmdline"
  1004. #endif
  1005.  
  1006. /*
  1007.  * readcmdline() - accept a command line starting with ':', '/', or '?' 
  1008.  *
  1009.  * readcmdline() accepts and processes colon commands and searches. If 'cmdline'
  1010.  * is null, the command line is read here. Otherwise, cmdline points to a
  1011.  * complete command line that should be used. This is used in main() to
  1012.  * handle initialization commands in the environment variable "EXINIT". 
  1013.  */
  1014. void
  1015. readcmdline(firstc, cmdline)
  1016.     char            firstc;    /* either ':', '/', or '?' */
  1017.     char           *cmdline;    /* optional command string */
  1018. {
  1019.     char            c;
  1020.     char            buff[CMDBUFFSIZE];
  1021.     char           *p, *q, *cmd, *arg;
  1022.     bool_t          literal_next_flag = FALSE;
  1023.  
  1024.     /*
  1025.      * Clear the range variables. 
  1026.      */
  1027.     l_pos.linep = (LINE *) NULL;
  1028.     u_pos.linep = (LINE *) NULL;
  1029.  
  1030.     interactive = (cmdline == NULL);
  1031.  
  1032.     if (interactive)
  1033.     gotocmdline(YES, firstc);
  1034.     p = buff;
  1035.     if (firstc != ':')
  1036.     *p++ = firstc;
  1037.  
  1038.     if (interactive) {
  1039.     /* collect the command string, handling '\b' and @ */
  1040.     for (;;) {
  1041.         c = vgetc();
  1042.         if (c == CTRL('V') && !literal_next_flag) {
  1043.         literal_next_flag = TRUE;
  1044.         outchar('^');
  1045.         continue;
  1046.         }
  1047.         if (c == '\n' || ((c == '\r' || c == ESC) && (!literal_next_flag)))
  1048.         break;
  1049.         if ((c == '\b') && (!literal_next_flag)) {
  1050.         if (p > buff) {
  1051.             p--;
  1052.             /*
  1053.              * this is gross, but it relies only on 'gotocmdline' 
  1054.              */
  1055.             gotocmdline(YES, firstc == ':' ? ':' : NUL);
  1056.             for (q = buff; q < p; q++)
  1057.             outstr(chars[*q].ch_str);
  1058.         } else {
  1059.             msg("");
  1060.             return;    /* back to cmd mode */
  1061.         }
  1062.         continue;
  1063.         }
  1064.         if ((c == '@') && (!literal_next_flag)) {
  1065.         p = buff;
  1066.         gotocmdline(YES, firstc);
  1067.         continue;
  1068.         }
  1069.         if (literal_next_flag) {
  1070.         literal_next_flag = FALSE;
  1071.         outchar('\b');
  1072.         }
  1073.         outstr(chars[c].ch_str);
  1074.         *p++ = c;
  1075.     }
  1076.     *p = '\0';
  1077.     } else {
  1078.     if (strlen(cmdline) > CMDBUFFSIZE - 2)    /* should really do something
  1079.                          * better here... */
  1080.         return;
  1081.     strcpy(p, cmdline);
  1082.     }
  1083.  
  1084.     /* skip any initial white space */
  1085.     for (cmd = buff; *cmd != NUL && isspace(*cmd); cmd++);
  1086.  
  1087.     /* search commands */
  1088.     c = *cmd;
  1089.     if (c == '/' || c == '?') {
  1090.     cmd++;
  1091.     /* was the command was '//' or '??' (I.E. repeat last search) */
  1092.     if ((*cmd == c) || (*cmd == NUL)) {
  1093.         if (c == '/')
  1094.         searchagain(FORWARD);
  1095.         else
  1096.         searchagain(BACKWARD);
  1097.         return;
  1098.     }
  1099.     /* If there is a matching '/' or '?' at the end, toss it */
  1100.     p = strchr(cmd, NUL);
  1101.     if (*(p - 1) == c && *(p - 2) != '\\')
  1102.         *(p - 1) = NUL;
  1103.     dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
  1104.     return;
  1105.     }
  1106.     /*
  1107.      * Parse a range, if present (and update the cmd pointer). 
  1108.      */
  1109.     get_range(&cmd);
  1110.  
  1111.     /* isolate the command and find any argument */
  1112.     for (p = cmd; *p != NUL && !isspace(*p); p++);
  1113.     if (*p == NUL)
  1114.     arg = NULL;
  1115.     else {
  1116.     *p = NUL;
  1117.     for (p++; *p != NUL && isspace(*p); p++);
  1118.     arg = p;
  1119.     if (*arg == NUL)
  1120.         arg = NULL;
  1121.     }
  1122.     if (strcmp(cmd, "q!") == 0)
  1123.     getout(0);
  1124.     if (strcmp(cmd, "q") == 0) {
  1125.     if (Changed)
  1126.         emsg(nowrtmsg);
  1127.     else
  1128.         getout(0);
  1129.     return;
  1130.     }
  1131.     if (strcmp(cmd, "w") == 0) {
  1132.     if (arg == NULL) {
  1133.         if (Filename != NULL) {
  1134.         writeit(Filename, &l_pos, &u_pos);
  1135.         UNCHANGED;
  1136.         } else
  1137.         emsg("No output file");
  1138.     } else
  1139.         writeit(arg, &l_pos, &u_pos);
  1140.     return;
  1141.     }
  1142.     if (strcmp(cmd, "wq") == 0) {
  1143.     if (Filename != NULL) {
  1144.         if (writeit(Filename, (LPTR *) NULL, (LPTR *) NULL))
  1145.         getout(0);
  1146.     } else
  1147.         emsg("No output file");
  1148.     return;
  1149.     }
  1150.     if (strcmp(cmd, "x") == 0) {
  1151.     if (Changed) {
  1152.         if (Filename != NULL) {
  1153.         if (!writeit(Filename, (LPTR *) NULL, (LPTR *) NULL))
  1154.             return;
  1155.         } else {
  1156.         emsg("No output file");
  1157.         return;
  1158.         }
  1159.     }
  1160.     getout(0);
  1161.     }
  1162.     if (strcmp(cmd, "f") == 0 && arg == NULL) {
  1163.     fileinfo();
  1164.     return;
  1165.     }
  1166.     if (*cmd == 'n') {
  1167.     if ((curfile + 1) < numfiles) {
  1168.         /*
  1169.          * stuff ":e[!] FILE\n" 
  1170.          */
  1171.         stuffReadbuff(":e");
  1172.         if (cmd[1] == '!')
  1173.         stuffReadbuff("!");
  1174.         stuffReadbuff(" ");
  1175.         stuffReadbuff(files[++curfile]);
  1176.         stuffReadbuff("\n");
  1177.     } else
  1178.         emsg("No more files!");
  1179.     return;
  1180.     }
  1181.     if (*cmd == 'p') {
  1182.     if (curfile > 0) {
  1183.         /*
  1184.          * stuff ":e[!] FILE\n" 
  1185.          */
  1186.         stuffReadbuff(":e");
  1187.         if (cmd[1] == '!')
  1188.         stuffReadbuff("!");
  1189.         stuffReadbuff(" ");
  1190.         stuffReadbuff(files[--curfile]);
  1191.         stuffReadbuff("\n");
  1192.     } else
  1193.         emsg("No more files!");
  1194.     return;
  1195.     }
  1196.     if (strncmp(cmd, "rew", 3) == 0) {
  1197.     if (numfiles <= 1)    /* nothing to rewind */
  1198.         return;
  1199.     curfile = 0;
  1200.     /*
  1201.      * stuff ":e[!] FILE\n" 
  1202.      */
  1203.     stuffReadbuff(":e");
  1204.     if (cmd[3] == '!')
  1205.         stuffReadbuff("!");
  1206.     stuffReadbuff(" ");
  1207.     stuffReadbuff(files[0]);
  1208.     stuffReadbuff("\n");
  1209.     return;
  1210.     }
  1211.     if (strcmp(cmd, "e") == 0 || strcmp(cmd, "e!") == 0) {
  1212.     doecmd(arg, cmd[1] == '!');
  1213.     return;
  1214.     }
  1215.     if (strcmp(cmd, "f") == 0) {
  1216.     Filename = strsave(arg);
  1217.     filemess("");
  1218.     return;
  1219.     }
  1220.     if (strcmp(cmd, "r") == 0 || strcmp(cmd, ".r") == 0) {
  1221.     if (arg == NULL) {
  1222.         badcmd();
  1223.         return;
  1224.     }
  1225.     if (readfile(arg, Curschar, 1)) {
  1226.         emsg("Can't open file");
  1227.         return;
  1228.     }
  1229.     updateNextscreen();
  1230.     CHANGED;
  1231.     return;
  1232.     }
  1233.     if (strcmp(cmd, ".=") == 0) {
  1234.     smsg("line %d", cntllines(Filemem, Curschar));
  1235.     return;
  1236.     }
  1237.     if (strcmp(cmd, "$=") == 0) {
  1238.     smsg("%d", cntllines(Filemem, Fileend) - 1);
  1239.     return;
  1240.     }
  1241.     if (strncmp(cmd, "ta", 2) == 0) {
  1242.     dotag(arg, cmd[2] == '!');
  1243.     return;
  1244.     }
  1245.     if (strcmp(cmd, "set") == 0) {
  1246.     doset(arg, interactive);
  1247.     return;
  1248.     }
  1249.     if (strcmp(cmd, "help") == 0) {
  1250.     if (help()) {
  1251.         screenclear();
  1252.         updateNextscreen();
  1253.     }
  1254.     return;
  1255.     }
  1256.     if (strcmp(cmd, "version") == 0) {
  1257.     extern char    *Version;
  1258.  
  1259.     msg(Version);
  1260.     return;
  1261.     }
  1262.     if (strcmp(cmd, "sh") == 0) {
  1263.     doshell();
  1264.     return;
  1265.     }
  1266.     /*
  1267.      * If we got a line, but no command, then go to the line. 
  1268.      */
  1269.     if (*cmd == NUL && l_pos.linep != NULL) {
  1270.     *Curschar = l_pos;
  1271.     cursupdate();
  1272.     return;
  1273.     }
  1274.     badcmd();
  1275. }
  1276.  
  1277. /*
  1278.  * get_range - parse a range specifier 
  1279.  *
  1280.  * Ranges are of the form: 
  1281.  *
  1282.  * addr[,addr] 
  1283.  *
  1284.  * where 'addr' is: 
  1285.  *
  1286.  * $  [+-NUM] 'x [+-NUM] (where x denotes a currently defined mark)
  1287.  * .  [+-NUM] NUM 
  1288.  *
  1289.  * The pointer *cp is updated to point to the first character following the
  1290.  * range spec. If an initial address is found, but no second, the upper bound
  1291.  * is equal to the lower. 
  1292.  */
  1293. static void
  1294. get_range(cp)
  1295.     char          **cp;
  1296. {
  1297.     LPTR           *l;
  1298.     char           *p;
  1299.  
  1300.     if ((l = get_line(cp)) == NULL)
  1301.     return;
  1302.  
  1303.     l_pos = *l;
  1304.  
  1305.     for (p = *cp; *p != NUL && isspace(*p); p++);
  1306.  
  1307.     *cp = p;
  1308.  
  1309.     if (*p != ',') {        /* is there another line spec ? */
  1310.     u_pos = l_pos;
  1311.     return;
  1312.     }
  1313.     *cp = ++p;
  1314.  
  1315.     if ((l = get_line(cp)) == NULL) {
  1316.     u_pos = l_pos;
  1317.     return;
  1318.     }
  1319.     u_pos = *l;
  1320. }
  1321.  
  1322. static LPTR    *
  1323. get_line(cp)
  1324.     char          **cp;
  1325. {
  1326.     static LPTR     pos;
  1327.     LPTR           *lp;
  1328.     char           *p, c;
  1329.     int             lnum;
  1330.  
  1331.     pos.index = 0;        /* shouldn't matter... check back later */
  1332.  
  1333.     p = *cp;
  1334.     /*
  1335.      * Determine the basic form, if present. 
  1336.      */
  1337.     switch (c = *p++) {
  1338.  
  1339.       case '$':
  1340.     pos.linep = Fileend->linep->prev;
  1341.     break;
  1342.  
  1343.       case '.':
  1344.     pos.linep = Curschar->linep;
  1345.     break;
  1346.  
  1347.       case '\'':
  1348.     if ((lp = getmark(*p++)) == NULL) {
  1349.         emsg("Unknown mark");
  1350.         return (LPTR *) NULL;
  1351.     }
  1352.     pos = *lp;
  1353.     break;
  1354.  
  1355.       case '0':
  1356.       case '1':
  1357.       case '2':
  1358.       case '3':
  1359.       case '4':
  1360.       case '5':
  1361.       case '6':
  1362.       case '7':
  1363.       case '8':
  1364.       case '9':
  1365.     for (lnum = c - '0'; isdigit(*p); p++)
  1366.         lnum = (lnum * 10) + (*p - '0');
  1367.  
  1368.     if (lnum == 0)
  1369.         lnum = 1;
  1370.  
  1371.     pos = *gotoline(lnum);
  1372.     break;
  1373.  
  1374.       default:
  1375.     return (LPTR *) NULL;
  1376.     }
  1377.  
  1378.     while (*p != NUL && isspace(*p))
  1379.     p++;
  1380.  
  1381.     if (*p == '-' || *p == '+') {
  1382.     bool_t          neg = (*p++ == '-');
  1383.  
  1384.     for (lnum = 0; isdigit(*p); p++)
  1385.         lnum = (lnum * 10) + (*p - '0');
  1386.  
  1387.     if (neg)
  1388.         lnum = -lnum;
  1389.  
  1390.     pos = *gotoline(cntllines(Filemem, &pos) + lnum);
  1391.     }
  1392.     *cp = p;
  1393.     return &pos;
  1394. }
  1395.  
  1396. static void
  1397. badcmd()
  1398. {
  1399.     if (interactive)
  1400.     emsg("Unrecognized command");
  1401. }
  1402.  
  1403. /*
  1404.  * dotag(tag, force) - goto tag 
  1405.  */
  1406. void
  1407. dotag(tag, force)
  1408.     char           *tag;
  1409.     bool_t          force;
  1410. {
  1411.     FILE           *tp, *fopen();
  1412.     char            lbuf[LSIZE];
  1413.     char           *fname, *str;
  1414.  
  1415.     if ((tp = fopen("tags", "r")) == NULL) {
  1416.     emsg("Can't open tags file");
  1417.     return;
  1418.     }
  1419.     while (fgets(lbuf, LSIZE, tp) != NULL) {
  1420.  
  1421.     if ((fname = strchr(lbuf, TAB)) == NULL) {
  1422.         emsg("Format error in tags file");
  1423.         return;
  1424.     }
  1425.     *fname++ = '\0';
  1426.     if ((str = strchr(fname, TAB)) == NULL) {
  1427.         emsg("Format error in tags file");
  1428.         return;
  1429.     }
  1430.     *str++ = '\0';
  1431.  
  1432.     if (strcmp(lbuf, tag) == 0) {
  1433.         if (doecmd(fname, force)) {
  1434.         stuffReadbuff(str);    /* str has \n at end */
  1435.         stuffReadbuff("\007");    /* CTRL('G') */
  1436.         fclose(tp);
  1437.         return;
  1438.         }
  1439.     }
  1440.     }
  1441.     emsg("tag not found");
  1442.     fclose(tp);
  1443. }
  1444.  
  1445. static          bool_t
  1446. doecmd(arg, force)
  1447.     char           *arg;
  1448.     bool_t          force;
  1449. {
  1450.     int             line = 1;    /* line # to go to in new file */
  1451.  
  1452.     if (!force && Changed) {
  1453.     emsg(nowrtmsg);
  1454.     return FALSE;
  1455.     }
  1456.     if (arg != NULL) {
  1457.     /*
  1458.      * First detect a ":e" on the current file. This is mainly for ":ta"
  1459.      * commands where the destination is within the current file. 
  1460.      */
  1461.     if (Filename != NULL && strcmp(arg, Filename) == 0) {
  1462.         if (!Changed || (Changed && !force))
  1463.         return TRUE;
  1464.     }
  1465.     if (strcmp(arg, "#") == 0) {    /* alternate */
  1466.         char           *s = Filename;
  1467.  
  1468.         if (altfile == NULL) {
  1469.         emsg("No alternate file");
  1470.         return FALSE;
  1471.         }
  1472.         Filename = altfile;
  1473.         altfile = s;
  1474.         line = altline;
  1475.         altline = cntllines(Filemem, Curschar);
  1476.     } else {
  1477.         altfile = Filename;
  1478.         altline = cntllines(Filemem, Curschar);
  1479.         Filename = strsave(arg);
  1480.     }
  1481.     }
  1482.     if (Filename == NULL) {
  1483.     emsg("No filename");
  1484.     return FALSE;
  1485.     }
  1486.     /* clear mem and read file */
  1487.     freeall();
  1488.     filealloc();
  1489.     UNCHANGED;
  1490.  
  1491.     readfile(Filename, Filemem, 0);
  1492.     *Topchar = *Curschar;
  1493.     if (line != 1) {
  1494.     stuffnumReadbuff(line);
  1495.     stuffReadbuff("G");
  1496.     }
  1497.     setpcmark();
  1498.     updateNextscreen();
  1499.     return TRUE;
  1500. }
  1501.  
  1502. static void
  1503. doshell()
  1504. {
  1505.     char           *sh, *getenv();
  1506.  
  1507.     sh = getenv("SHELL");
  1508.     if (sh == NULL) {
  1509.     emsg("Shell variable not set");
  1510.     return;
  1511.     }
  1512.     gotocmdline(YES, NUL);
  1513.  
  1514.     if (system(sh) < 0) {
  1515.     emsg("Exec failed");
  1516.     return;
  1517.     }
  1518.     wait_return();
  1519. }
  1520.  
  1521. void
  1522. gotocmdline(clr, firstc)
  1523.     bool_t          clr;
  1524.     char            firstc;
  1525. {
  1526.     windgoto(Rows - 1, 0);
  1527.     if (clr)
  1528.     outstr(T_EL);        /* clear the bottom line */
  1529.     if (firstc)
  1530.     outchar(firstc);
  1531. }
  1532.  
  1533. /*
  1534.  * msg(s) - displays the string 's' on the status line 
  1535.  */
  1536. void
  1537. msg(s)
  1538.     char           *s;
  1539. {
  1540.     gotocmdline(YES, NUL);
  1541.     outstr(s);
  1542. #ifdef AMIGA
  1543.     fflush(stdout);
  1544. #endif
  1545. #ifdef BSD
  1546.     fflush(stdout);
  1547. #endif
  1548. }
  1549.  
  1550. /* VARARGS */
  1551. void
  1552. smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  1553.     char           *s;
  1554.     int             a1, a2, a3, a4, a5, a6, a7, a8, a9;
  1555. {
  1556.     char            sbuf[MAX_COLUMNS + 1];
  1557.  
  1558.     sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  1559.     msg(sbuf);
  1560. }
  1561.  
  1562. /*
  1563.  * emsg() - display an error message 
  1564.  *
  1565.  * Rings the bell, if appropriate, and calls message() to do the real work 
  1566.  */
  1567. void
  1568. emsg(s)
  1569.     char           *s;
  1570. {
  1571.     UndoInProgress = FALSE;
  1572.     RedrawingDisabled = FALSE;
  1573.     ResetBuffers();
  1574.  
  1575.     if (P(P_EB))
  1576.     beep();
  1577.     outstr(T_TI);
  1578.     msg(s);
  1579.     outstr(T_TP);
  1580. #ifdef AMIGA
  1581.     fflush(stdout);
  1582. #endif
  1583. #ifdef BSD
  1584.     fflush(stdout);
  1585. #endif
  1586. }
  1587.  
  1588. void
  1589. wait_return()
  1590. {
  1591.     char            c;
  1592.  
  1593.     outstr("Press RETURN to continue");
  1594.     do {
  1595.     c = vgetc();
  1596.     } while (c != '\r' && c != '\n');
  1597.  
  1598.     screenclear();
  1599.     updateNextscreen();
  1600. }
  1601. SHAR_EOF
  1602. cat << \SHAR_EOF > dec.c
  1603. /*
  1604.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  1605.  *
  1606.  * Code Contributions By : Tim Thompson           twitch!tjt
  1607.  *                         Tony Andrews           onecom!wldrdg!tony 
  1608.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  1609.  */
  1610.  
  1611. #include "stevie.h"
  1612.  
  1613. /*
  1614.  * dec(p) 
  1615.  *
  1616.  * Decrement the line pointer 'p' crossing line boundaries as necessary. Return
  1617.  * 1 when crossing a line, -1 when at start of file, 0 otherwise. 
  1618.  */
  1619. int
  1620. dec(lp)
  1621.     LPTR           *lp;
  1622. {
  1623.     if (lp->index > 0) {    /* still within line */
  1624.     lp->index--;
  1625.     return 0;
  1626.     }
  1627.     if (lp->linep->prev != NULL) {    /* there is a prior line */
  1628.     lp->linep = lp->linep->prev;
  1629.     lp->index = strlen(lp->linep->s);
  1630.     return 1;
  1631.     }
  1632.     return -1;            /* at start of file */
  1633. }
  1634. SHAR_EOF
  1635. cat << \SHAR_EOF > edit.c
  1636. /*
  1637.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  1638.  *
  1639.  * Code Contributions By : Tim Thompson           twitch!tjt
  1640.  *                         Tony Andrews           onecom!wldrdg!tony 
  1641.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  1642.  */
  1643.  
  1644. #include "stevie.h"
  1645.  
  1646. /*
  1647.  * This flag is used to make auto-indent work right on lines where only a
  1648.  * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
  1649.  * reset when any other editting is done on the line. If an <ESC> or <RETURN>
  1650.  * is received, and did_ai is TRUE, the line is truncated. 
  1651.  */
  1652. bool_t          did_ai = FALSE;
  1653.  
  1654. void
  1655. edit()
  1656. {
  1657.     char            c;
  1658.     bool_t          literal_next_flag = FALSE;
  1659.  
  1660.     Prenum = 0;
  1661.  
  1662.     /* position the display and the cursor at the top of the file. */
  1663.     *Topchar = *Filemem;
  1664.     *Curschar = *Filemem;
  1665.     Cursrow = Curscol = 0;
  1666.  
  1667.     for (;;) {
  1668.  
  1669.     if (!RedrawingDisabled) {
  1670.         cursupdate();    /* Figure out where the cursor is based on
  1671.                  * Curschar. */
  1672.         if (MustRedrawLine)
  1673.         redrawline();
  1674.         if (MustRedrawScreen)
  1675.         updateRealscreen();
  1676.  
  1677.         windgoto(Cursrow, Curscol);
  1678.     }
  1679.     c = vgetc();
  1680.  
  1681.     if (State == NORMAL) {
  1682.         /* We're in the normal (non-insert) mode. */
  1683.  
  1684.         /* Pick up any leading digits and compute 'Prenum' */
  1685.         if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
  1686.         Prenum = Prenum * 10 + (c - '0');
  1687.         continue;
  1688.         }
  1689.         /* execute the command */
  1690.         normal(c);
  1691.         Prenum = 0;
  1692.  
  1693.     } else {
  1694.         if (c == CTRL('V') && !literal_next_flag) {
  1695.         literal_next_flag = TRUE;
  1696.         outchar('^');
  1697.         continue;
  1698.         }
  1699.         if (literal_next_flag) {
  1700.         literal_next_flag = FALSE;
  1701.         outchar('\b');
  1702.         if (c != NL) {
  1703.             did_ai = FALSE;
  1704.             insertchar(c);
  1705.             continue;
  1706.         }
  1707.         }
  1708.         switch (c) {    /* We're in insert mode */
  1709.  
  1710.           case CR:
  1711.           case NL:
  1712.         *Insbuffptr++ = NL;
  1713.         *Insbuffptr = NUL;
  1714.         if (!opencmd(FORWARD, TRUE))
  1715.             goto doESCkey;    /* out of memory */
  1716.  
  1717.         if (!RedrawingDisabled)
  1718.             windgoto(Cursrow, Curscol);
  1719.         break;
  1720.  
  1721.           case ESC:    /* an escape ends input mode */
  1722.     doESCkey:
  1723.         set_want_col = TRUE;
  1724.  
  1725.         /* Don't end up on a '\n' if you can help it. */
  1726.         if (gchar(Curschar) == NUL && Curschar->index != 0)
  1727.             dec(Curschar);
  1728.  
  1729.         /*
  1730.          * The cursor should end up on the last inserted character.
  1731.          * This is an attempt to match the real 'vi', but it may not
  1732.          * be quite right yet. 
  1733.          */
  1734.         if (Curschar->index != 0 && !endofline(Curschar))
  1735.             dec(Curschar);
  1736.  
  1737.         State = NORMAL;
  1738.         msg("");
  1739.  
  1740.         if (!UndoInProgress) {
  1741.             int             n;
  1742.             char           *p;
  1743.  
  1744.             if (last_command == 'o')
  1745.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  1746.  
  1747.             if (Insbuff != Insbuffptr) {
  1748.             if (last_command == 'O')
  1749.                 AppendToUndobuff("0");
  1750.             AppendToRedobuff(Insbuff);
  1751.             AppendToUndoUndobuff(Insbuff);
  1752.             n = 0;
  1753.             for (p = Insbuff; p < Insbuffptr; p++) {
  1754.                 if (*p == NL) {
  1755.                 if (n) {
  1756.                     AppendNumberToUndobuff(n);
  1757.                     AppendToUndobuff("dl");
  1758.                     n = 0;
  1759.                 }
  1760.                 AppendToUndobuff(UNDO_SHIFTJ_STR);
  1761.                 } else
  1762.                 n++;
  1763.             }
  1764.             if (n) {
  1765.                 AppendNumberToUndobuff(n);
  1766.                 AppendToUndobuff("dl");
  1767.             }
  1768.             }
  1769.             if (last_command == 'c') {
  1770.             AppendToUndobuff(mkstr(last_command_char));
  1771.             AppendToUndobuff(Yankbuff);
  1772.             AppendToUndobuff(ESC_STR);
  1773.             }
  1774.             AppendToRedobuff(ESC_STR);
  1775.             AppendToUndoUndobuff(ESC_STR);
  1776.             if (last_command == 'O')
  1777.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  1778.         }
  1779.         break;
  1780.  
  1781.           case CTRL('D'):
  1782.         /*
  1783.          * Control-D is treated as a backspace in insert mode to make
  1784.          * auto-indent easier. This isn't completely compatible with
  1785.          * vi, but it's a lot easier than doing it exactly right, and
  1786.          * the difference isn't very noticeable. 
  1787.          */
  1788.           case BS:
  1789.         /* can't backup past starting point */
  1790.         if (Curschar->linep == Insstart->linep &&
  1791.             Curschar->index <= Insstart->index) {
  1792.             beep();
  1793.             break;
  1794.         }
  1795.         /* can't backup to a previous line */
  1796.         if (Curschar->linep != Insstart->linep &&
  1797.             Curschar->index <= 0) {
  1798.             beep();
  1799.             break;
  1800.         }
  1801.         did_ai = FALSE;
  1802.         dec(Curschar);
  1803.         delchar(TRUE, FALSE);
  1804.         Insbuffptr--;
  1805.         *Insbuffptr = NUL;
  1806.         cursupdate();
  1807.         updateline();
  1808.         break;
  1809.  
  1810.           default:
  1811.         did_ai = FALSE;
  1812.         insertchar(c);
  1813.         break;
  1814.         }
  1815.     }
  1816.     }
  1817. }
  1818.  
  1819. /*
  1820.  * Special characters in this context are those that need processing other
  1821.  * than the simple insertion that can be performed here. This includes ESC
  1822.  * which terminates the insert, and CR/NL which need special processing to
  1823.  * open up a new line. This routine tries to optimize insertions performed by
  1824.  * the "redo" command, so it needs to know when it should stop and defer
  1825.  * processing to the "normal" mechanism. 
  1826.  */
  1827. #define    ISSPECIAL(c)    ((c) == NL || (c) == CR || (c) == ESC)
  1828.  
  1829. void
  1830. insertchar(c)
  1831.     char            c;
  1832. {
  1833.     if (anyinput()) {        /* If there's any pending input, grab it all
  1834.                  * at once. */
  1835.     char           *p;
  1836.  
  1837.     p = Insbuffptr;
  1838.     *Insbuffptr++ = c;
  1839.     for (c = vpeekc(); !ISSPECIAL(c) && anyinput(); c = vpeekc()) {
  1840.         c = vgetc();
  1841.         *Insbuffptr++ = c;
  1842.         /*
  1843.          * The following kludge avoids overflowing the insert buffer. 
  1844.          */
  1845.         if (Insbuffptr + 10 >= &Insbuff[INSERT_SIZE]) {
  1846.         int             n;
  1847.  
  1848.         *Insbuffptr = NUL;
  1849.         insstr(p);
  1850.  
  1851.         Insbuffptr = Insbuff;
  1852.         p = Insbuffptr;
  1853.  
  1854.         emsg("Insert buffer overflow - buffers flushed");
  1855.         sleep(2);
  1856.  
  1857.         n = cntllines(Filemem, Curschar);
  1858.         AppendPositionToUndobuff(Curschar->index, n);
  1859.         AppendPositionToUndoUndobuff(Curschar->index, n);
  1860.         if (endofline(Curschar)) {
  1861.             AppendToRedobuff("a");
  1862.             AppendToUndoUndobuff("a");
  1863.         } else {
  1864.             AppendToRedobuff("i");
  1865.             AppendToUndoUndobuff("i");
  1866.         }
  1867.         }
  1868.     }
  1869.     *Insbuffptr = NUL;
  1870.     insstr(p);
  1871.     } else {
  1872.     inschar(c);
  1873.     *Insbuffptr++ = c;
  1874.  
  1875.     /*
  1876.      * The following kludge avoids overflowing the insert buffer. 
  1877.      */
  1878.     if (Insbuffptr + 10 >= &Insbuff[INSERT_SIZE]) {
  1879.         int             n;
  1880.  
  1881.         Insbuffptr = Insbuff;
  1882.  
  1883.         emsg("Insert buffer overflow - buffers flushed");
  1884.         sleep(2);
  1885.  
  1886.         n = cntllines(Filemem, Curschar);
  1887.         AppendPositionToUndobuff(Curschar->index, n);
  1888.         AppendPositionToUndoUndobuff(Curschar->index, n);
  1889.         if (endofline(Curschar)) {
  1890.         AppendToRedobuff("a");
  1891.         AppendToUndoUndobuff("a");
  1892.         } else {
  1893.         AppendToRedobuff("i");
  1894.         AppendToUndoUndobuff("i");
  1895.         }
  1896.     }
  1897.     *Insbuffptr = NUL;
  1898.     }
  1899.  
  1900.     updateline();
  1901. }
  1902.  
  1903. void
  1904. getout(r)
  1905.     int             r;
  1906. {
  1907.     windgoto(Rows - 1, 0);
  1908.     putchar('\r');
  1909.     putchar('\n');
  1910.     windexit(r);
  1911. }
  1912.  
  1913. void
  1914. scrolldown(nlines)
  1915.     int             nlines;
  1916. {
  1917.     LPTR           *p;
  1918.     int             done = 0;    /* total # of physical lines done */
  1919.  
  1920.     /* Scroll up 'nlines' lines. */
  1921.     while (nlines--) {
  1922.     if ((p = prevline(Topchar)) == NULL)
  1923.         break;
  1924.     done += plines(p);
  1925.     *Topchar = *p;
  1926.     if (Curschar->linep == Botchar->linep->prev)
  1927.         *Curschar = *prevline(Curschar);
  1928.     }
  1929.     s_ins(0, done);
  1930. }
  1931.  
  1932. void
  1933. scrollup(nlines)
  1934.     int             nlines;
  1935. {
  1936.     LPTR           *p;
  1937.     int             done = 0;    /* total # of physical lines done */
  1938.     int             pl;        /* # of plines for the current line */
  1939.  
  1940.     /* Scroll down 'nlines' lines. */
  1941.     while (nlines--) {
  1942.     pl = plines(Topchar);
  1943.     if ((p = nextline(Topchar)) == NULL)
  1944.         break;
  1945.     done += pl;
  1946.     if (Curschar->linep == Topchar->linep)
  1947.         *Curschar = *p;
  1948.     *Topchar = *p;
  1949.  
  1950.     }
  1951.     s_del(0, done);
  1952. }
  1953.  
  1954. /*
  1955.  * oneright oneleft onedown oneup 
  1956.  *
  1957.  * Move one char {right,left,down,up}.  Return TRUE when sucessful, FALSE when
  1958.  * we hit a boundary (of a line, or the file). 
  1959.  */
  1960.  
  1961. bool_t
  1962. oneright()
  1963. {
  1964.     set_want_col = TRUE;
  1965.  
  1966.     switch (inc(Curschar)) {
  1967.  
  1968.       case 0:
  1969.     return TRUE;
  1970.  
  1971.       case 1:
  1972.     dec(Curschar);        /* crossed a line, so back up */
  1973.     /* FALLTHROUGH */
  1974.       case -1:
  1975.     return FALSE;
  1976.     }
  1977.  
  1978.     return FALSE;        /* PARANOIA: should never reach here */
  1979. }
  1980.  
  1981. bool_t
  1982. oneleft()
  1983. {
  1984.     set_want_col = TRUE;
  1985.  
  1986.     switch (dec(Curschar)) {
  1987.  
  1988.       case 0:
  1989.     return TRUE;
  1990.  
  1991.       case 1:
  1992.     inc(Curschar);        /* crossed a line, so back up */
  1993.     /* FALLTHROUGH */
  1994.       case -1:
  1995.     return FALSE;
  1996.     }
  1997.  
  1998.     return FALSE;        /* PARANOIA: should never reach here */
  1999. }
  2000.  
  2001. void
  2002. beginline(flag)
  2003.     bool_t          flag;
  2004. {
  2005.     while (oneleft());
  2006.     if (flag) {
  2007.     while (isspace(gchar(Curschar)) && oneright());
  2008.     }
  2009.     set_want_col = TRUE;
  2010. }
  2011.  
  2012. bool_t
  2013. oneup(n)
  2014. {
  2015.     LPTR            p, *np;
  2016.     int             k;
  2017.  
  2018.     p = *Curschar;
  2019.     for (k = 0; k < n; k++) {
  2020.     /* Look for the previous line */
  2021.     if ((np = prevline(&p)) == NULL) {
  2022.         /* If we've at least backed up a little .. */
  2023.         if (k > 0)
  2024.         break;        /* to update the cursor, etc. */
  2025.         else
  2026.         return FALSE;
  2027.     }
  2028.     p = *np;
  2029.     }
  2030.     *Curschar = p;
  2031.  
  2032.     cursupdate();        /* make sure Topchar is valid */
  2033.  
  2034.     /* try to advance to the column we want to be at */
  2035.     *Curschar = *coladvance(&p, Curswant);
  2036.     return TRUE;
  2037. }
  2038.  
  2039. bool_t
  2040. onedown(n)
  2041. {
  2042.     LPTR            p, *np;
  2043.     int             k;
  2044.  
  2045.     p = *Curschar;
  2046.     for (k = 0; k < n; k++) {
  2047.     /* Look for the next line */
  2048.     if ((np = nextline(&p)) == NULL) {
  2049.         if (k > 0)
  2050.         break;
  2051.         else
  2052.         return FALSE;
  2053.     }
  2054.     p = *np;
  2055.     }
  2056.  
  2057.     cursupdate();        /* make sure Topchar is valid */
  2058.  
  2059.     /* try to advance to the column we want to be at */
  2060.     *Curschar = *coladvance(&p, Curswant);
  2061.     return TRUE;
  2062. }
  2063. SHAR_EOF
  2064. cat << \SHAR_EOF > fileio.c
  2065. /*
  2066.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  2067.  *
  2068.  * Code Contributions By : Tim Thompson           twitch!tjt
  2069.  *                         Tony Andrews           onecom!wldrdg!tony 
  2070.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  2071.  */
  2072.  
  2073. #include "stevie.h"
  2074.  
  2075. void
  2076. filemess(s)
  2077.     char           *s;
  2078. {
  2079.     sprintf(IObuff, "\"%s\" %s", ((Filename == NULL) ? "" : Filename), s);
  2080.     msg(IObuff);
  2081. }
  2082.  
  2083. void
  2084. renum()
  2085. {
  2086.     LPTR           *p;
  2087.     unsigned int    l = 0;
  2088.  
  2089.     for (p = Filemem; p != NULL; p = nextline(p), l += LINEINC)
  2090.     p->linep->num = l;
  2091.  
  2092.     Fileend->linep->num = 0xffff;
  2093. }
  2094.  
  2095. #ifdef    MEGAMAX
  2096. overlay "fileio"
  2097. #endif
  2098.  
  2099. bool_t
  2100. readfile(fname, fromp, nochangename)
  2101.     char           *fname;
  2102.     LPTR           *fromp;
  2103.     bool_t          nochangename;    /* if TRUE, don't change the Filename */
  2104. {
  2105.     FILE           *f, *fopen();
  2106.     LINE           *curr;
  2107.     char           *p;
  2108.     int             i, c;
  2109.     long            nchars;
  2110.     int             unprint = 0;
  2111.     int             linecnt = 0;
  2112.     bool_t          wasempty = bufempty();
  2113.  
  2114.     curr = fromp->linep;
  2115.  
  2116.     if (!nochangename)
  2117.     Filename = strsave(fname);
  2118.  
  2119.     if ((f = fopen(fname, "r")) == NULL)
  2120.     return TRUE;
  2121.  
  2122.     filemess("");
  2123.  
  2124.     i = 0;
  2125.     for (nchars = 0; (c = getc(f)) != EOF; nchars++) {
  2126.     if (c >= 0x80) {
  2127.         c -= 0x80;
  2128.         unprint++;
  2129.     }
  2130.     /*
  2131.      * Nulls are special, so they can't show up in the file. We should
  2132.      * count nulls seperate from other nasties, but this is okay for now. 
  2133.      */
  2134.     if (c == NUL) {
  2135.         unprint++;
  2136.         continue;
  2137.     }
  2138.     if (c == '\n') {    /* process the completed line */
  2139.         int             len;
  2140.         LINE           *lp;
  2141.  
  2142.         IObuff[i] = NUL;
  2143.         len = strlen(IObuff) + 1;
  2144.         if ((lp = newline(len)) == NULL) {
  2145.         fprintf(stderr, "not enough memory - should never happen");
  2146.         getout(1);
  2147.         }
  2148.         strcpy(lp->s, IObuff);
  2149.  
  2150.         curr->next->prev = lp;    /* new line to next one */
  2151.         lp->next = curr->next;
  2152.  
  2153.         curr->next = lp;    /* new line to prior one */
  2154.         lp->prev = curr;
  2155.  
  2156.         curr = lp;        /* new line becomes current */
  2157.         i = 0;
  2158.         linecnt++;
  2159.     } else
  2160.         IObuff[i++] = (char) c;
  2161.     }
  2162.     fclose(f);
  2163.  
  2164.     /*
  2165.      * If the buffer was empty when we started, we have to go back and remove
  2166.      * the "dummy" line at Filemem and patch up the ptrs. 
  2167.      */
  2168.     if (wasempty) {
  2169.     LINE           *dummy = Filemem->linep;    /* dummy line ptr */
  2170.  
  2171.     free(dummy->s);        /* free string space */
  2172.     Filemem->linep = Filemem->linep->next;
  2173.     free((char *) dummy);    /* free LINE struct */
  2174.     Filemem->linep->prev = NULL;
  2175.  
  2176.     Curschar->linep = Filemem->linep;
  2177.     Topchar->linep = Filemem->linep;
  2178.     }
  2179.     if (unprint > 0)
  2180.     p = "\"%s\" %d lines, %ld characters (%d un-printable))";
  2181.     else
  2182.     p = "\"%s\" %d lines, %ld characters";
  2183.  
  2184.     sprintf(IObuff, p, fname, linecnt, nchars, unprint);
  2185.     msg(IObuff);
  2186.     renum();
  2187.     return FALSE;
  2188. }
  2189.  
  2190.  
  2191. /*
  2192.  * writeit - write to file 'fname' lines 'start' through 'end' 
  2193.  *
  2194.  * If either 'start' or 'end' contain null line pointers, the default is to use
  2195.  * the start or end of the file respectively. 
  2196.  */
  2197. bool_t
  2198. writeit(fname, start, end)
  2199.     char           *fname;
  2200.     LPTR           *start, *end;
  2201. {
  2202.     FILE           *f, *fopen();
  2203.     FILE           *fopenb();    /* open in binary mode, where needed */
  2204.     char            backup[16], *s;
  2205.     long            nchars;
  2206.     int             lines;
  2207.     LPTR           *p;
  2208.  
  2209.     sprintf(IObuff, "\"%s\"", fname);
  2210.     msg(IObuff);
  2211.  
  2212.     /*
  2213.      * Form the backup file name - change foo.* to foo.bak 
  2214.      */
  2215.     strcpy(backup, fname);
  2216.     for (s = backup; *s && *s != '.'; s++);
  2217.     *s = NUL;
  2218.     strcat(backup, ".bak");
  2219.  
  2220.     /*
  2221.      * Delete any existing backup and move the current version to the backup.
  2222.      * For safety, we don't remove the backup until the write has finished
  2223.      * successfully. And if the 'backup' option is set, leave it around. 
  2224.      */
  2225.     rename(fname, backup);
  2226.  
  2227.  
  2228.     f = P(P_CR) ? fopen(fname, "w") : fopenb(fname, "w");
  2229.  
  2230.     if (f == NULL) {
  2231.     emsg("Can't open file for writing!");
  2232.     return FALSE;
  2233.     }
  2234.     /*
  2235.      * If we were given a bound, start there. Otherwise just start at the
  2236.      * beginning of the file. 
  2237.      */
  2238.     if (start == NULL || start->linep == NULL)
  2239.     p = Filemem;
  2240.     else
  2241.     p = start;
  2242.  
  2243.     lines = 0;
  2244.     nchars = 0;
  2245.     do {
  2246.     fprintf(f, "%s\n", p->linep->s);
  2247.     nchars += strlen(p->linep->s) + 1;
  2248.     lines++;
  2249.  
  2250.     /*
  2251.      * If we were given an upper bound, and we just did that line, then
  2252.      * bag it now. 
  2253.      */
  2254.     if (end != NULL && end->linep != NULL) {
  2255.         if (end->linep == p->linep)
  2256.         break;
  2257.     }
  2258.     } while ((p = nextline(p)) != NULL);
  2259.  
  2260.     fclose(f);
  2261.     sprintf(IObuff, "\"%s\" %d lines, %ld characters", fname, lines, nchars);
  2262.     msg(IObuff);
  2263.     UNCHANGED;
  2264.  
  2265.     /*
  2266.      * Remove the backup unless they want it left around 
  2267.      */
  2268.     if (!P(P_BK))
  2269.     remove(backup);
  2270.  
  2271.     return TRUE;
  2272. }
  2273. SHAR_EOF
  2274. cat << \SHAR_EOF > help.c
  2275. /*
  2276.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  2277.  *
  2278.  * Code Contributions By : Tim Thompson           twitch!tjt
  2279.  *                         Tony Andrews           onecom!wldrdg!tony 
  2280.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  2281.  */
  2282.  
  2283. #include "stevie.h"
  2284.  
  2285. char           *Version = "STEVIE - Version 3.10a";
  2286.  
  2287. static int      helprow;
  2288.  
  2289. #ifdef    HELP
  2290.  
  2291. #ifdef    MEGAMAX
  2292. overlay "help"
  2293. #endif
  2294.  
  2295. static void     longline();
  2296.  
  2297. bool_t
  2298. help()
  2299. {
  2300.  
  2301.     /***********************************************************************
  2302.          * First Screen:   Positioning within file, Adjusting the Screen
  2303.          ***********************************************************************/
  2304.  
  2305.     outstr(T_ED);
  2306.     windgoto(helprow = 0, 0);
  2307.  
  2308.     longline("\
  2309.    Positioning within file\n\
  2310.    =======================\n\
  2311.       ^F             Forward screenfull             Worked on by:\n\
  2312.       ^B             Backward screenfull                Tim Thompson\n");
  2313.     longline("\
  2314.       ^D             scroll down half screen            Tony Andrews\n\
  2315.       ^U             scroll up half screen              G.R. (Fred) Walter\n");
  2316.     longline("\
  2317.       G              Goto line (end default)\n\
  2318.       ]]             next function\n\
  2319.       [[             previous function\n\
  2320.       /re            next occurence of regular expression 're'\n");
  2321.     longline("\
  2322.       ?re            prior occurence of regular expression 're'\n\
  2323.       n              repeat last / or ?\n\
  2324.       N              reverse last / or ?\n\
  2325.       %              find matching (, ), {, }, [, or ]\n");
  2326.     longline("\
  2327. \n\
  2328.    Adjusting the screen\n\
  2329.    ====================\n\
  2330.       ^L             Redraw the screen\n\
  2331.       ^E             scroll window down 1 line\n\
  2332.       ^Y             scroll window up 1 line\n");
  2333.     longline("\
  2334.       z<RETURN>      redraw, current line at top\n\
  2335.       z-             ... at bottom\n\
  2336.       z.             ... at center\n");
  2337.  
  2338.     windgoto(0, 52);
  2339.     longline(Version);
  2340.  
  2341.     windgoto(helprow = Rows - 2, 47);
  2342.     longline("<Press space bar to continue>\n");
  2343.     windgoto(helprow = Rows - 1, 47);
  2344.     longline("<Any other key will quit>");
  2345.  
  2346.     if (vgetc() != ' ')
  2347.     return TRUE;
  2348.  
  2349.     /***********************************************************************
  2350.          * Second Screen:   Character positioning
  2351.          ***********************************************************************/
  2352.  
  2353.     outstr(T_ED);
  2354.     windgoto(helprow = 0, 0);
  2355.  
  2356.     longline("\
  2357.    Character Positioning\n\
  2358.    =====================\n\
  2359.       ^              first non-white\n\
  2360.       0              beginning of line\n\
  2361.       $              end of line\n\
  2362.       h              backward\n");
  2363.     longline("\
  2364.       l              forward\n\
  2365.       ^H             same as h\n\
  2366.       space          same as l\n\
  2367.       fx             find 'x' forward\n");
  2368.     longline("\
  2369.       Fx             find 'x' backward\n\
  2370.       tx             upto 'x' forward\n\
  2371.       Tx             upto 'x' backward\n\
  2372.       ;              Repeat last f, F, t, or T\n");
  2373.     longline("\
  2374.       ,              inverse of ;\n\
  2375.       |              to specified column\n\
  2376.       %              find matching (, ), {, }, [, or ]\n");
  2377.  
  2378.     windgoto(helprow = Rows - 2, 47);
  2379.     longline("<Press space bar to continue>\n");
  2380.     windgoto(helprow = Rows - 1, 47);
  2381.     longline("<Any other key will quit>");
  2382.  
  2383.     if (vgetc() != ' ')
  2384.     return TRUE;
  2385.  
  2386.     /***********************************************************************
  2387.          * Third Screen:   Line Positioning, Marking and Returning
  2388.          ***********************************************************************/
  2389.  
  2390.     outstr(T_ED);
  2391.     windgoto(helprow = 0, 0);
  2392.  
  2393.     longline("\
  2394.     Line Positioning\n\
  2395.     =====================\n\
  2396.     H           home window line\n\
  2397.     L           last window line\n\
  2398.     M           middle window line\n");
  2399.     longline("\
  2400.     +           next line, at first non-white\n\
  2401.     -           previous line, at first non-white\n\
  2402.     CR          return, same as +\n\
  2403.     j           next line, same column\n\
  2404.     k           previous line, same column\n");
  2405.  
  2406.     longline("\
  2407. \n\
  2408.     Marking and Returning\n\
  2409.     =====================\n\
  2410.     ``          previous context\n\
  2411.     ''          ... at first non-white in line\n");
  2412.     longline("\
  2413.     mx          mark position with letter 'x'\n\
  2414.     `x          to mark 'x'\n\
  2415.     'x          ... at first non-white in line\n");
  2416.  
  2417.     windgoto(helprow = Rows - 2, 47);
  2418.     longline("<Press space bar to continue>\n");
  2419.     windgoto(helprow = Rows - 1, 47);
  2420.     longline("<Any other key will quit>");
  2421.  
  2422.     if (vgetc() != ' ')
  2423.     return TRUE;
  2424.     /***********************************************************************
  2425.          * Fourth Screen:   Insert & Replace, 
  2426.          ***********************************************************************/
  2427.  
  2428.     outstr(T_ED);
  2429.     windgoto(helprow = 0, 0);
  2430.  
  2431.     longline("\
  2432.     Insert and Replace\n\
  2433.     ==================\n\
  2434.     a           append after cursor\n\
  2435.     i           insert before cursor\n\
  2436.     A           append at end of line\n\
  2437.     I           insert before first non-blank\n");
  2438.     longline("\
  2439.     o           open line below\n\
  2440.     O           open line above\n\
  2441.     rx          replace single char with 'x'\n\
  2442.     R           replace characters (not yet)\n\
  2443.     ~           replace character under cursor with other case\n");
  2444.  
  2445.     longline("\
  2446. \n\
  2447.     Words, sentences, paragraphs\n\
  2448.     ============================\n\
  2449.     w           word forward\n\
  2450.     b           back word\n\
  2451.     e           end of word\n\
  2452.     )           to next sentence (not yet)\n\
  2453.     }           to next paragraph (not yet)\n");
  2454.     longline("\
  2455.     (           back sentence (not yet)\n\
  2456.     {           back paragraph (not yet)\n\
  2457.     W           blank delimited word\n\
  2458.     B           back W\n\
  2459.     E           to end of W");
  2460.  
  2461.     windgoto(helprow = Rows - 2, 47);
  2462.     longline("<Press space bar to continue>\n");
  2463.     windgoto(helprow = Rows - 1, 47);
  2464.     longline("<Any other key will quit>");
  2465.  
  2466.     if (vgetc() != ' ')
  2467.     return TRUE;
  2468.  
  2469.     /***********************************************************************
  2470.          * Fifth Screen:   Misc. operations, 
  2471.          ***********************************************************************/
  2472.  
  2473.     outstr(T_ED);
  2474.     windgoto(helprow = 0, 0);
  2475.  
  2476.     longline("\
  2477.     Undo  &  Redo\n\
  2478.     =============\n\
  2479.     u           undo last change\n\
  2480.     U           restore current line (not yet)\n\
  2481.     .           repeat last change\n");
  2482.  
  2483.     longline("\
  2484. \n\
  2485.     File manipulation\n\
  2486.     =================\n");
  2487.     longline("\
  2488.     :w          write back changes\n\
  2489.     :wq         write and quit\n\
  2490.     :x          write if modified, and quit\n\
  2491.     :q          quit\n\
  2492.     :q!         quit, discard changes\n\
  2493.     :e name     edit file 'name'\n");
  2494.     longline("\
  2495.     :e!         reedit, discard changes\n\
  2496.     :e #        edit alternate file\n\
  2497.     :w name     write file 'name'\n");
  2498.     longline("\
  2499.     :n          edit next file in arglist\n\
  2500.     :n args     specify new arglist (not yet)\n\
  2501.     :rew        rewind arglist\n\
  2502.     :f          show current file and lines\n");
  2503.     longline("\
  2504.     :f file     change current file name\n\
  2505.     :ta tag     to tag file entry 'tag'\n\
  2506.     ^]          :ta, current word is tag");
  2507.  
  2508.     windgoto(helprow = Rows - 2, 47);
  2509.     longline("<Press space bar to continue>\n");
  2510.     windgoto(helprow = Rows - 1, 47);
  2511.     longline("<Any other key will quit>");
  2512.  
  2513.     if (vgetc() != ' ')
  2514.     return TRUE;
  2515.  
  2516.     /***********************************************************************
  2517.          * Sixth Screen:   Operators, Misc. operations, Yank & Put
  2518.          ***********************************************************************/
  2519.  
  2520.     outstr(T_ED);
  2521.     windgoto(helprow = 0, 0);
  2522.  
  2523.     longline("\
  2524.     Operators (double to affect lines)\n\
  2525.     ==================================\n\
  2526.     d           delete\n\
  2527.     c           change\n");
  2528.     longline("\
  2529.     <           left shift\n\
  2530.     >           right shift\n\
  2531.     y           yank to buffer\n");
  2532.  
  2533.     longline("\n\
  2534.     Miscellaneous operations\n\
  2535.     ========================\n\
  2536.     C           change rest of line\n\
  2537.     D           delete rest of line\n\
  2538.     s           substitute chars\n");
  2539.     longline("\
  2540.     S           substitute lines (not yet)\n\
  2541.     J           join lines\n\
  2542.     x           delete characters\n\
  2543.     X           ... before cursor\n");
  2544.  
  2545.     longline("\n\
  2546.     Yank and Put\n\
  2547.     ============\n\
  2548.     p           put back text\n\
  2549.     P           put before\n\
  2550.     Y           yank lines");
  2551.  
  2552.     windgoto(helprow = Rows - 1, 47);
  2553.     longline("<Press any key>");
  2554.  
  2555.     vgetc();
  2556.  
  2557.     return TRUE;
  2558. }
  2559.  
  2560. static void
  2561. longline(p)
  2562.     char           *p;
  2563. {
  2564. # ifdef AMIGA
  2565.     outstr(p);
  2566. # else
  2567.     char           *s;
  2568.  
  2569.     for (s = p; *s; s++) {
  2570.     if (*s == '\n')
  2571.         windgoto(++helprow, 0);
  2572.     else
  2573.         outchar(*s);
  2574.     }
  2575. # endif
  2576. }
  2577. #else
  2578.  
  2579. bool_t
  2580. help()
  2581. {
  2582.     msg("Sorry, help not configured");
  2583.     return FALSE;
  2584. }
  2585. #endif
  2586. SHAR_EOF
  2587. cat << \SHAR_EOF > inc.c
  2588. /*
  2589.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  2590.  *
  2591.  * Code Contributions By : Tim Thompson           twitch!tjt
  2592.  *                         Tony Andrews           onecom!wldrdg!tony 
  2593.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  2594.  */
  2595.  
  2596. #include "stevie.h"
  2597.  
  2598. /*
  2599.  * inc(p) 
  2600.  *
  2601.  * Increment the line pointer 'p' crossing line boundaries as necessary. Return
  2602.  * 1 when crossing a line, -1 when at end of file, 0 otherwise. 
  2603.  */
  2604. int
  2605. inc(lp)
  2606.     LPTR           *lp;
  2607. {
  2608.     char           *p = &(lp->linep->s[lp->index]);
  2609.  
  2610.     if (*p != NUL) {        /* still within line */
  2611.     lp->index++;
  2612.     return ((p[1] != NUL) ? 0 : 1);
  2613.     }
  2614.     if (lp->linep->next != Fileend->linep) {    /* there is a next line */
  2615.     lp->index = 0;
  2616.     lp->linep = lp->linep->next;
  2617.     return 1;
  2618.     }
  2619.     return -1;
  2620. }
  2621. SHAR_EOF
  2622. #    End of shell archive
  2623. exit 0
  2624. -- 
  2625. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2626. Have five nice days.
  2627.